G_OBJECT_CLASS (gdk_clipboard_parent_class)->finalize (object);
}
+static void
+gdk_clipboard_real_read_async (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (clipboard, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+ g_task_set_source_tag (task, gdk_clipboard_read_async);
+ g_task_set_task_data (task, gdk_content_formats_ref (formats), (GDestroyNotify) gdk_content_formats_unref);
+
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Reading local content not supported yet.");
+ g_object_unref (task);
+}
+
static GInputStream *
-gdk_clipboard_real_read (GdkClipboard *clipboard,
- const char *mime_type)
+gdk_clipboard_real_read_finish (GdkClipboard *clipboard,
+ const char **out_mime_type,
+ GAsyncResult *result,
+ GError **error)
{
/* whoop whooop */
return g_memory_input_stream_new ();
object_class->set_property = gdk_clipboard_set_property;
object_class->finalize = gdk_clipboard_finalize;
- class->read = gdk_clipboard_real_read;
+ class->read_async = gdk_clipboard_real_read_async;
+ class->read_finish = gdk_clipboard_real_read_finish;
/**
* GdkClipboard:display:
return priv->formats;
}
-GInputStream *
-gdk_clipboard_read (GdkClipboard *clipboard,
- const char *mime_type)
+static void
+gdk_clipboard_read_internal (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard);
+ return GDK_CLIPBOARD_GET_CLASS (clipboard)->read_async (clipboard,
+ formats,
+ io_priority,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * gdk_clipboard_read_async:
+ * @clipboard: a #GdkClipboard
+ * @mime_types: a %NULL-terminated array of mime types to choose from
+ * @io_priority: the [I/O priority][io-priority]
+ * of the request.
+ * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
+ * @callback: (scope async): callback to call when the request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously requests an input stream to read the @clipboard's
+ * contents from. When the operation is finished @callback will be called.
+ * You can then call gdk_clipboard_read_finish() to get the result of the
+ * operation.
+ *
+ * The clipboard will choose the most suitable mime type from the given list
+ * to fulfill the request, preferring the ones listed first.
+ **/
+void
+gdk_clipboard_read_async (GdkClipboard *clipboard,
+ const char **mime_types,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkContentFormats *formats;
+
+ g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
+ g_return_if_fail (mime_types != NULL && mime_types[0] != NULL);
+ g_return_if_fail (callback != NULL);
+
+ formats = gdk_content_formats_new (mime_types, g_strv_length ((char **) mime_types));
+
+ gdk_clipboard_read_internal (clipboard, formats, io_priority, cancellable, callback, user_data);
+
+ gdk_content_formats_unref (formats);
+}
+/**
+ * gdk_clipboard_read_finish:
+ * @clipboard: a #GdkClipboard
+ * @out_mime_type: (out) (allow-none) (transfer none): pointer to store
+ * the chosen mime type in or %NULL
+ * @result: a #GAsyncResult
+ * @error: a #GError location to store the error occurring, or %NULL to
+ * ignore.
+ *
+ * Finishes an asynchronous clipboard read started with gdk_clipboard_read_async().
+ *
+ * Returns: (transfer full): a #GInputStream or %NULL on error.
+ **/
+GInputStream *
+gdk_clipboard_read_finish (GdkClipboard *clipboard,
+ const char **out_mime_type,
+ GAsyncResult *result,
+ GError **error)
+{
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
- g_return_val_if_fail (mime_type != NULL, NULL);
- g_return_val_if_fail (gdk_content_formats_contain_mime_type (priv->formats, mime_type), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- return GDK_CLIPBOARD_GET_CLASS (clipboard)->read (clipboard, mime_type);
+ return GDK_CLIPBOARD_GET_CLASS (clipboard)->read_finish (clipboard, out_mime_type, result, error);
}
GdkClipboard *
GdkContentFormats * gdk_clipboard_get_formats (GdkClipboard *clipboard);
GDK_AVAILABLE_IN_3_94
-GInputStream * gdk_clipboard_read (GdkClipboard *clipboard,
- const char *mime_type);
+void gdk_clipboard_read_async (GdkClipboard *clipboard,
+ const char **mime_types,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDK_AVAILABLE_IN_3_94
+GInputStream * gdk_clipboard_read_finish (GdkClipboard *clipboard,
+ const char **out_mime_type,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
void (* changed) (GdkClipboard *clipboard);
/* vfuncs */
- GInputStream * (* read) (GdkClipboard *clipboard,
- const char *mime_type);
+ void (* read_async) (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GInputStream * (* read_finish) (GdkClipboard *clipboard,
+ const char **out_mime_type,
+ GAsyncResult *result,
+ GError **error);
};
GdkClipboard * gdk_clipboard_new (GdkDisplay *display);
guint i, n_atoms;
bytes = g_input_stream_read_bytes_finish (stream, res, &error);
- if (bytes == NULL || g_bytes_get_size (bytes) == 0)
+ if (bytes == NULL)
{
- if (bytes)
- g_bytes_unref (bytes);
+ g_error_free (error);
+ g_object_unref (stream);
+ g_object_unref (cb);
+ return;
+ }
+ else if (g_bytes_get_size (bytes) == 0)
+ {
+ g_bytes_unref (bytes);
g_object_unref (stream);
g_object_unref (cb);
return;
}
static void
-gdk_x11_clipboard_request_targets (GdkX11Clipboard *cb)
+gdk_x11_clipboard_request_targets_got_stream (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
{
+ GdkX11Clipboard *cb = data;
GInputStream *stream;
GdkDisplay *display;
-
- display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+ GError *error = NULL;
+
+ stream = gdk_x11_selection_input_stream_new_finish (result, &error);
+ if (stream == NULL)
+ {
+ g_object_unref (cb);
+ return;
+ }
- stream = gdk_x11_selection_input_stream_new (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
- cb->selection,
- "TARGETS",
- cb->timestamp);
+ display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
g_input_stream_read_bytes_async (stream,
SELECTION_MAX_SIZE (display),
G_PRIORITY_DEFAULT,
NULL,
gdk_x11_clipboard_request_targets_finish,
- g_object_ref (cb));
+ cb);
+}
+
+static void
+gdk_x11_clipboard_request_targets (GdkX11Clipboard *cb)
+{
+ gdk_x11_selection_input_stream_new_async (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
+ cb->selection,
+ "TARGETS",
+ cb->timestamp,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ gdk_x11_clipboard_request_targets_got_stream,
+ g_object_ref (cb));
}
static GdkFilterReturn
G_OBJECT_CLASS (gdk_x11_clipboard_parent_class)->finalize (object);
}
-static GInputStream *
-gdk_x11_clipboard_read (GdkClipboard *clipboard,
- const char *mime_type)
+static void
+gdk_x11_clipboard_read_got_stream (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GTask *task = data;
+ GError *error = NULL;
+ GInputStream *stream;
+
+ stream = gdk_x11_selection_input_stream_new_finish (res, &error);
+ /* XXX: We could try more types here */
+ if (stream == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, stream, g_object_unref);
+
+ g_object_unref (task);
+}
+
+static void
+gdk_x11_clipboard_read_async (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (clipboard);
+ const char * const *mime_types;
+ GTask *task;
+
+ task = g_task_new (clipboard, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+ g_task_set_source_tag (task, gdk_x11_clipboard_read_async);
+ g_task_set_task_data (task, gdk_content_formats_ref (formats), (GDestroyNotify) gdk_content_formats_unref);
+
+ /* XXX: Sort differently? */
+ mime_types = gdk_content_formats_get_mime_types (formats, NULL);
+
+ gdk_x11_selection_input_stream_new_async (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
+ cb->selection,
+ mime_types[0],
+ cb->timestamp,
+ io_priority,
+ cancellable,
+ gdk_x11_clipboard_read_got_stream,
+ task);
+}
+
+static GInputStream *
+gdk_x11_clipboard_read_finish (GdkClipboard *clipboard,
+ const char **out_mime_type,
+ GAsyncResult *result,
+ GError **error)
+{
+ GInputStream *stream;
+ GTask *task;
+
+ g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (clipboard)), NULL);
+ task = G_TASK (result);
+ g_return_val_if_fail (g_task_get_source_tag (task) == gdk_x11_clipboard_read_async, NULL);
+
+ stream = g_task_propagate_pointer (task, error);
+
+ if (stream)
+ {
+ if (out_mime_type)
+ {
+ GdkContentFormats *formats;
+ const char * const *mime_types;
+
+ formats = g_task_get_task_data (task);
+ mime_types = gdk_content_formats_get_mime_types (formats, NULL);
+ *out_mime_type = mime_types[0];
+ }
+ g_object_ref (stream);
+ }
+ else
+ {
+ if (out_mime_type)
+ *out_mime_type = NULL;
+ }
- return gdk_x11_selection_input_stream_new (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
- cb->selection,
- mime_type,
- cb->timestamp);
+ return stream;
}
static void
object_class->finalize = gdk_x11_clipboard_finalize;
- clipboard_class->read = gdk_x11_clipboard_read;
+ clipboard_class->read_async = gdk_x11_clipboard_read_async;
+ clipboard_class->read_finish = gdk_x11_clipboard_read_finish;
}
static void
case SelectionNotify:
{
+ GTask *task;
+ /* selection is not for us */
if (priv->xselection != xevent->xselection.selection ||
priv->xtarget != xevent->xselection.target)
return GDK_FILTER_CONTINUE;
+ /* We already received a selectionNotify before */
+ if (priv->pending_task == NULL ||
+ g_task_get_source_tag (priv->pending_task) != gdk_x11_selection_input_stream_new_async)
+ return GDK_FILTER_CONTINUE;
+
GDK_NOTE(SELECTION, g_print ("%s:%s: got SelectionNotify\n", priv->selection, priv->target));
- if (xevent->xselection.property != None)
- bytes = get_selection_property (xdisplay, xwindow, xevent->xselection.property, &type, &format);
- else
- bytes = NULL;
+ task = priv->pending_task;
+ priv->pending_task = NULL;
- if (bytes == NULL)
- {
+ if (xevent->xselection.property == None)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ _("Format %s not supported"), priv->target);
gdk_x11_selection_input_stream_complete (stream);
}
else
{
- if (type == gdk_x11_get_xatom_by_name_for_display (priv->display, "INCR"))
- {
- /* The remainder of the selection will come through PropertyNotify
- events on xwindow */
- GDK_NOTE(SELECTION, g_print ("%s:%s: initiating INCR transfer\n", priv->selection, priv->target));
- priv->incr = TRUE;
- gdk_x11_selection_input_stream_flush (stream);
+ bytes = get_selection_property (xdisplay, xwindow, xevent->xselection.property, &type, &format);
+
+ g_task_return_pointer (task, g_object_ref (stream), g_object_unref);
+
+ if (bytes == NULL)
+ {
+ gdk_x11_selection_input_stream_complete (stream);
}
else
{
- g_async_queue_push (priv->chunks, bytes);
-
- gdk_x11_selection_input_stream_complete (stream);
+ if (priv->xtype == gdk_x11_get_xatom_by_name_for_display (priv->display, "INCR"))
+ {
+ /* The remainder of the selection will come through PropertyNotify
+ events on xwindow */
+ GDK_NOTE(SELECTION, g_print ("%s:%s: initiating INCR transfer\n", priv->selection, priv->target));
+ priv->incr = TRUE;
+ gdk_x11_selection_input_stream_flush (stream);
+ }
+ else
+ {
+ g_async_queue_push (priv->chunks, bytes);
+
+ gdk_x11_selection_input_stream_complete (stream);
+ }
}
XDeleteProperty (xdisplay, xwindow, xevent->xselection.property);
}
- }
+
+ g_object_unref (task);
+ }
return GDK_FILTER_REMOVE;
default:
}
}
-GInputStream *
-gdk_x11_selection_input_stream_new (GdkDisplay *display,
- const char *selection,
- const char *target,
- guint32 timestamp)
+void
+gdk_x11_selection_input_stream_new_async (GdkDisplay *display,
+ const char *selection,
+ const char *target,
+ guint32 timestamp,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GdkX11SelectionInputStream *stream;
GdkX11SelectionInputStreamPrivate *priv;
-
+
stream = g_object_new (GDK_TYPE_X11_SELECTION_INPUT_STREAM, NULL);
priv = gdk_x11_selection_input_stream_get_instance_private (stream);
GDK_X11_DISPLAY (display)->leader_window,
timestamp);
- return g_object_ref (stream);
+ priv->pending_task = g_task_new (NULL, cancellable, callback, user_data);
+ g_task_set_source_tag (priv->pending_task, gdk_x11_selection_input_stream_new_async);
+ g_task_set_priority (priv->pending_task, io_priority);
+}
+
+GInputStream *
+gdk_x11_selection_input_stream_new_finish (GAsyncResult *result,
+ GError **error)
+{
+ GInputStream *stream;
+ GTask *task;
+
+ g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
+ task = G_TASK (result);
+ g_return_val_if_fail (g_task_get_source_tag (task) == gdk_x11_selection_input_stream_new_async, NULL);
+
+ stream = g_task_propagate_pointer (task, error);
+ if (stream)
+ g_object_ref (stream);
+ return stream;
}
GType gdk_x11_selection_input_stream_get_type (void) G_GNUC_CONST;
-GInputStream * gdk_x11_selection_input_stream_new (GdkDisplay *display,
- const char *selection,
- const char *target,
- guint32 timestamp);
+void gdk_x11_selection_input_stream_new_async (GdkDisplay *display,
+ const char *selection,
+ const char *target,
+ guint32 timestamp,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GInputStream * gdk_x11_selection_input_stream_new_finish (GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
g_object_unref (pixbuf);
}
+static void
+clipboard_read_pixbuf_cb (GObject *clipboard,
+ GAsyncResult *result,
+ gpointer image)
+{
+ GInputStream *stream;
+ GError *error = NULL;
+
+ stream = gdk_clipboard_read_finish (GDK_CLIPBOARD (clipboard),
+ NULL,
+ result,
+ &error);
+ if (stream)
+ {
+ gdk_pixbuf_new_from_stream_async (stream, NULL, pixbuf_loaded_cb, image);
+ g_object_unref (stream);
+ }
+ else
+ {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ }
+}
+
static void
visible_child_changed_cb (GtkWidget *stack,
GParamSpec *pspec,
else if (g_str_equal (visible_child, "image"))
{
GtkWidget *image = gtk_stack_get_child_by_name (GTK_STACK (stack), "image");
- GdkContentFormats *formats;
- GInputStream *stream;
-
- formats = gdk_clipboard_get_formats (clipboard);
- if (gdk_content_formats_contain_mime_type (formats, "image/png"))
- stream = gdk_clipboard_read (clipboard, "image/png");
- else
- stream = NULL;
- if (stream)
- {
- gdk_pixbuf_new_from_stream_async (stream, NULL, pixbuf_loaded_cb, image);
- g_object_unref (stream);
- }
+
+ gdk_clipboard_read_async (clipboard,
+ (const gchar*[2]) { "image/png", NULL },
+ G_PRIORITY_DEFAULT,
+ NULL,
+ clipboard_read_pixbuf_cb,
+ image);
}
}